﻿
(function($) {

    //Utility
    function clone(obj) {
        var objClone;
        if (obj.constructor == Object) {
            objClone = new obj.constructor();
        } else {
            objClone = new obj.constructor(obj.valueOf());
        }
        for (var key in obj) {
            if (objClone[key] != obj[key]) {
                if (typeof (obj[key]) == 'object') {
                    objClone[key] = clone(obj[key]);
                } else {
                    objClone[key] = obj[key];
                }
            }
        }
        objClone.toString = obj.toString;
        objClone.valueOf = obj.valueOf;
        return objClone;
    }

    function tryeach(obj, fn, context) {
        if (obj == null)
            return;
        else if (jQuery.isArray(obj))
            jQuery.each(obj, function() { fn.call(context, this); });
        else
            fn.call(context, obj);
    }

    // treeforms defined
    window.treeforms = {};
    // treeforms utility
    treeforms.createNode = function(name, parentNode) {
        var doc = null;
        if (parentNode != null) {
            if (parentNode.createElement != null)
                doc = parentNode;
            else if (parentNode.ownerDocument != null)
                doc = parentNode.ownerDocument;
            else
                doc = zXmlDom.createDocument();
        } else {
            doc = zXmlDom.createDocument();
        }
        return doc.createElement(name);
    }
    treeforms.merge = function(first, second) {

        (function recus(arg1, arg2) {

            var arg2Childs = $(arg2).children();

            jQuery.each(arg2Childs, function(i) {
                var child1 = zXPath.selectSingleNode(arg1, this.tagName);
                var child2 = this;

                if (child1 == null) {
                    $(arg1).append(child2);
                } else if ($(child1).text() == null) {
                    $(child1).text($(child2).text());
                } else {
                    recus(child1, child2);
                }

            });
        })(first, second);
    },

    treeforms.mapping = function() { this.initialize.apply(this, arguments); };
    treeforms.mapping.prototype = {
        initialize: function(args) {
            this.tree = args.tree;
            this.commit = args.commit;
            this.forms = args.forms;

            this.treeReady(onTreeReady);

            function onTreeReady() {
                this.formReady(onFormReady);
            }

            function onFormReady() {

            }
        },
        treeReady: function(callback) {
            var thisObj = this;
            if (jQuery.isFunction(this.tree)) {
                this.tree(function(tree) {
                    thisObj.tree = tree;
                    callback();
                });
            } else if (this.tree != null) {
                callback();
            }
        },
        formReady: function(callback) {

            this.forms = treeforms.forms.initialize(this.forms);
            // to recursive with build
            this.forms.traversing(this, function(mapping) {
                return treeforms.forms.initialize(this, mapping);
            });
            // to recursive with initialize
            this.forms.traversing(function() {
                this.ready();
            });
        }
    };

    treeforms.forms = function() { this.initialize.apply(this, arguments); };
    treeforms.forms.prototype = {
        initialize: function(args) {
            jQuery.extend(this, args[0]);
        },
        traversing: function(arg, callback, direction) {
            if (arguments.length == 1) {
                callback = arg;
                arg = null;
            }
            (function recus(path, current) {
                current.children = jQuery.map(current.children, function() {
                    this.formpath = this.formpath || path + this.name;
                    var result;
                    if (direction != false) {
                        var result = fn.call(this, args) || this;
                        recus(path + current.name + "/", this);
                    } else {
                        recus(path + current.name + "/", this);
                        var result = fn.call(this, args) || this;
                    }
                    return result;
                });
            })("/", this);
        },
        backtracking: function(arg, callback) {
            if (arguments.length == 1) {
                callback = arg;
                arg = null;
            }
            (function recus(path, current) {
                current.formpath = current.formpath || current.name + path;
                current = fn.call(current, args) || current;
                if (current.parent != null)
                    recus("/" + current.name + path, current.parent);
            })("/", this);
        }
    };

    // { element: ".class", event: { click: "refresh" } }
    treeforms.listening = function() { this.initialize.call(this, arguments); };
    treeforms.listening.prototype = {
        initialize: function(define) {
            jQuery.extend(this, define);
        }
    };
    // { click: "refresh" }
    treeforms.event = function() { this.initialize.call(this, arguments[0], arguments[1]); };
    treeforms.event.prototype = {
        initialize: function(define, element) {
            if (define.name != null)
                jQuery.extend(this, define);
            else {
                var thisObj = this;
                jQuery.each(define, function(name, val) {
                    thisObj.name = name;
                    thisObj.action = val;
                    return false;
                });
            }
            if (this.name == null || this.action == null)
                throw "define type is illegal.";

            this.element = element;
            if (!jQuery.isFunction(this.action)) {
                var action_name = this.action;
                this.action = function() { $(this).triggerHandler(action_name); };
            }
            $(this.element).bind(this.name, this.action);
        }
    };

    treeforms.action = function() { this.initialize.call(this, arguments[0], arguments[1]); };
    treeforms.action.prototype = {
        initialize: function(define, listening) {
            jQuery.extend(this, define);
        }
    };

})(jQuery);